Micron Document
NexusPi Git Node

Commit 8dca5d50cc0c634d1dbd4ccdda20e1ba07593e7d


Parents : 68fed6e
Author : James L <jrl290@gmail.com>
Date : 2026-04-26T20:38:20-04:00

Remove V4 8MB build; delete make_release.py

- platformio.ini: remove [env:heltec_V4_boundary] (8MB) env block
- flash.py: remove 8MB flash_variant from V4 BOARD_PROFILES; V4 is 16MB only
- Makefile: remove heltec_V4_boundary from release-pio target
- extra_script.py: remove heltec32v4_boundary from variant list
- README.md: update build commands to heltec_V4_boundary_16mb
- make_release.py: deleted (releases handled manually)

Changes

6 files changed, 5 insertions(+), 391 deletions(-)

M Makefile +1 -2
M README.md +3 -3
M flash.py -6

Diff

diff --git a/Makefile b/Makefile
index 1a68229..414a163 100755
--- a/Makefile
+++ b/Makefile
@@ -286,11 +286,10 @@ release-all: console-site spiffs-image release-tbeam release-tbeam_sx1262 releas
# The archive (rtnode_firmware.zip) is the primary distribution artefact consumed
# by flash.py. Individual binaries are stored flat inside the zip.
release-pio:
- pio run -e heltec_V4_boundary -e heltec_V4_boundary_16mb -e heltec_V3_boundary
+ pio run -e heltec_V4_boundary_16mb -e heltec_V3_boundary
python3 -c "\
import zipfile, os, sys; \
variants = [ \
- ('.pio/build/heltec_V4_boundary', 'rnode_firmware_heltec32v4_boundary_8mb.bin'), \
('.pio/build/heltec_V4_boundary_16mb', 'rnode_firmware_heltec32v4_boundary_16mb.bin'), \
('.pio/build/heltec_V3_boundary', 'rnode_firmware_heltec32v3.bin'), \
]; \

diff --git a/README.md b/README.md
index 587f290..3f811cd 100755
--- a/README.md
+++ b/README.md
@@ -88,13 +88,13 @@ git clone https://github.com/jrl290/RTNode-HeltecV4.git
cd RTNode-HeltecV4
# Build for V4
-pio run -e heltec_V4_boundary
+pio run -e heltec_V4_boundary_16mb
# Build for V3
pio run -e heltec_V3_boundary
# Flash (via PlatformIO)
-pio run -e heltec_V4_boundary -t upload
+pio run -e heltec_V4_boundary_16mb -t upload
# Or create a merged binary and flash with the utility
python flash.py --merge-only # creates merged firmware bin
@@ -364,7 +364,7 @@ Set the transport node's **Local TCP Server** to **Enabled** (port 4242).
| `Display.h` | OLED display layout — transport node status page |
| `flash.py` | Flash utility — list serial ports, download from GitHub, merge & flash firmware |
| `Boards.h` | Board variant definitions for V3 and V4 |
-| `platformio.ini` | Build targets: `heltec_V3_boundary`, `heltec_V4_boundary`, and `heltec_V4_boundary-local` |
+| `platformio.ini` | Build targets: `heltec_V3_boundary`, `heltec_V4_boundary_16mb`, and `heltec_V4_boundary-local` |
### Library Patches

diff --git a/extra_script.py b/extra_script.py
index 0ebcec2..0fba4c5 100755
--- a/extra_script.py
+++ b/extra_script.py
@@ -119,7 +119,7 @@ def device_provision(env):
env.Execute("rnodeconf --product e0 --model e9 --hwrev 1 --rom " + env.subst("$UPLOAD_PORT"))
elif variant in ("lora32v21", "lora32v21_local"):
env.Execute("rnodeconf --product b1 --model b9 --hwrev 1 --rom " + env.subst("$UPLOAD_PORT"))
- elif variant in ("heltec32v4", "heltec32v4_local", "heltec32v4_boundary", "heltec32v4_boundary_local"):
+ elif variant in ("heltec32v4", "heltec32v4_local", "heltec32v4_boundary_local"):
env.Execute("rnodeconf --product b1 --model b9 --hwrev 1 --rom " + env.subst("$UPLOAD_PORT"))
elif variant in ("rak4631", "rak4631_local"):
env.Execute("rnodeconf --product 10 --model 12 --hwrev 1 --rom " + env.subst("$UPLOAD_PORT"))

diff --git a/flash.py b/flash.py
index 47bcdbc..8bfc2f8 100755
--- a/flash.py
+++ b/flash.py
@@ -88,12 +88,6 @@ BOARD_PROFILES = {
"baud_rate": "921600",
"flash_mode": "qio", # ESP32-S3 PSRAM requires QIO — DIO disables PSRAM
"flash_variants": {
- "8MB": {
- "pio_env": "heltec_V4_boundary",
- "build_dir": ".pio/build/heltec_V4_boundary",
- "firmware_bin": "rnode_firmware_heltec32v4_boundary_8mb.bin",
- "merged_bin": "rnode_firmware_heltec32v4_boundary_8mb_merged.bin",
- },
"16MB": {
"pio_env": "heltec_V4_boundary_16mb",
"build_dir": ".pio/build/heltec_V4_boundary_16mb",

diff --git a/make_release.py b/make_release.py
deleted file mode 100644
index 0b19217..0000000
--- a/make_release.py
+++ /dev/null
@@ -1,344 +0,0 @@
-#!/usr/bin/env python3
-"""
-make_release.py — RTNode-HeltecV4 Release Packager
-
-Builds all firmware variants with PlatformIO, merges each into a self-contained
-binary (bootloader + partitions + boot_app0 + app), and packages everything
-into a single ZIP archive ready for publishing on GitHub Releases.
-
-The resulting archive contains:
- - flash.py (flasher utility — no PlatformIO required to use)
- - README.md (release notes / instructions)
- - rnode_firmware_*_merged.bin (one pre-merged binary per board/flash-size)
- - esptool/<binary> (added separately — platform-specific standalone binary)
-
-Usage:
- python make_release.py # build all envs and package
- python make_release.py --no-build # skip pio build (use existing .pio/build output)
- python make_release.py --output myfile.zip
-
-The standalone esptool binary is NOT included automatically (it is platform-specific).
-Copy it to Release/esptool/esptool (or esptool/esptool) before or after running
-this script, then add it to the ZIP manually or via CI.
-"""
-
-import argparse
-import hashlib
-import json
-import os
-import platform
-import re
-import shutil
-import subprocess
-import sys
-import zipfile
-
-# ── Configuration ──────────────────────────────────────────────────────────────
-
-SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
-OUTPUT_ZIP = os.path.join(SCRIPT_DIR, "Release", "rtnode_firmware.zip")
-
-# Environments to build and merge. Maps PIO env → merged binary name.
-BUILD_ENVS = [
- {
- "pio_env": "heltec_V3_boundary",
- "build_dir": ".pio/build/heltec_V3_boundary",
- "firmware_bin": "rnode_firmware_heltec32v3.bin",
- "merged_bin": "rnode_firmware_heltec32v3_merged.bin",
- "chip": "esp32s3",
- "flash_mode": "dio",
- "flash_freq": "80m",
- "flash_size": "8MB",
- "board_name": "Heltec V3 (8MB)",
- },
- {
- "pio_env": "heltec_V4_boundary",
- "build_dir": ".pio/build/heltec_V4_boundary",
- "firmware_bin": "rnode_firmware_heltec32v4_boundary_8mb.bin",
- "merged_bin": "rnode_firmware_heltec32v4_boundary_8mb_merged.bin",
- "chip": "esp32s3",
- "flash_mode": "qio",
- "flash_freq": "80m",
- "flash_size": "8MB",
- "board_name": "Heltec V4 (8MB)",
- },
- {
- "pio_env": "heltec_V4_boundary_16mb",
- "build_dir": ".pio/build/heltec_V4_boundary_16mb",
- "firmware_bin": "rnode_firmware_heltec32v4_boundary_16mb.bin",
- "merged_bin": "rnode_firmware_heltec32v4_boundary_16mb_merged.bin",
- "chip": "esp32s3",
- "flash_mode": "qio",
- "flash_freq": "80m",
- "flash_size": "16MB",
- "board_name": "Heltec V4 (16MB)",
- },
-]
-
-# Boot component addresses
-BOOTLOADER_ADDR = 0x0000
-PARTITIONS_ADDR = 0x8000
-BOOT_APP0_ADDR = 0xe000
-APP_ADDR = 0x10000
-
-# Files included in the ZIP alongside the firmware binaries
-EXTRA_FILES = [
- ("flash.py", "flash.py"),
- ("README.md", "README.md"),
-]
-
-
-def find_pio():
- """Return the PlatformIO executable path."""
- for name in ("pio", "platformio"):
- path = shutil.which(name)
- if path:
- return path
- return None
-
-
-def find_esptool():
- """Return an esptool command list for merge_bin operations."""
- exe_name = "esptool.exe" if platform.system() == "Windows" else "esptool"
-
- # Prefer PlatformIO bundled esptool (always present when PIO is installed)
- candidates = [
- os.path.expanduser("~/.platformio/packages/tool-esptoolpy/esptool.py"),
- ]
- for c in candidates:
- if os.path.isfile(c):
- return [sys.executable, c]
-
- # Fall back to system esptool
- for name in ("esptool.py", "esptool"):
- if shutil.which(name):
- return [name]
-
- # Release standalone binary
- for rel in (os.path.join(SCRIPT_DIR, "esptool", exe_name),
- os.path.join(SCRIPT_DIR, "Release", "esptool", exe_name)):
- if os.path.isfile(rel) and os.access(rel, os.X_OK):
- return [rel]
-
- return None
-
-
-def find_boot_app0():
- """Return path to boot_app0.bin from PlatformIO framework."""
- pio_dir = os.path.expanduser("~/.platformio/packages")
- if os.path.isdir(pio_dir):
- for name in sorted(os.listdir(pio_dir), reverse=True):
- if name.startswith("framework-arduinoespressif32"):
- candidate = os.path.join(pio_dir, name, "tools", "partitions", "boot_app0.bin")
- if os.path.isfile(candidate):
- return candidate
- return None
-
-
-def sha256_file(path):
- h = hashlib.sha256()
- with open(path, "rb") as f:
- for chunk in iter(lambda: f.read(65536), b""):
- h.update(chunk)
- return h.hexdigest()
-
-
-def build_env(env_cfg, pio):
- """Run `pio run -e <env>` and return True on success."""
- env = env_cfg["pio_env"]
- print(f"\n Building {env_cfg['board_name']} (env: {env})...")
- result = subprocess.run([pio, "run", "-e", env], cwd=SCRIPT_DIR)
- if result.returncode != 0:
- print(f" ERROR: Build failed for {env}")
- return False
- fw = os.path.join(SCRIPT_DIR, env_cfg["build_dir"], env_cfg["firmware_bin"])
- if not os.path.isfile(fw):
- print(f" ERROR: Firmware not found after build: {fw}")
- return False
- print(f" OK: {fw}")
- return True
-
-
-def merge_env(env_cfg, esptool_cmd, boot_app0):
- """Merge bootloader + partitions + boot_app0 + app into a single binary."""
- build_dir = os.path.join(SCRIPT_DIR, env_cfg["build_dir"])
- bootloader = os.path.join(build_dir, "bootloader.bin")
- partitions = os.path.join(build_dir, "partitions.bin")
- firmware = os.path.join(build_dir, env_cfg["firmware_bin"])
- merged_out = os.path.join(build_dir, env_cfg["merged_bin"])
-
- missing = []
- if not os.path.isfile(bootloader): missing.append(bootloader)
- if not os.path.isfile(partitions): missing.append(partitions)
- if not boot_app0: missing.append("boot_app0.bin (not found)")
- if not os.path.isfile(firmware): missing.append(firmware)
- if missing:
- print(f" ERROR: Missing components for {env_cfg['board_name']}:")
- for m in missing:
- print(f" {m}")
- return None
-
- print(f" Merging {env_cfg['board_name']}...")
- cmd = esptool_cmd + [
- "--chip", env_cfg["chip"],
- "merge_bin",
- "--flash_mode", env_cfg["flash_mode"],
- "--flash_freq", env_cfg["flash_freq"],
- "--flash_size", env_cfg["flash_size"],
- "-o", merged_out,
- f"0x{BOOTLOADER_ADDR:x}", bootloader,
- f"0x{PARTITIONS_ADDR:x}", partitions,
- f"0x{BOOT_APP0_ADDR:x}", boot_app0,
- f"0x{APP_ADDR:x}", firmware,
- ]
- result = subprocess.run(cmd, capture_output=True, text=True, cwd=SCRIPT_DIR)
- if result.returncode != 0:
- print(f" ERROR: merge_bin failed:\n{result.stderr}{result.stdout}")
- return None
-
- size = os.path.getsize(merged_out)
- digest = sha256_file(merged_out)
- print(f" OK: {env_cfg['merged_bin']} ({size:,} bytes) sha256:{digest[:16]}...")
- return merged_out
-
-
-def read_version():
- """Read MAJ_VERS + MIN_VERS from Config.h."""
- cfg = os.path.join(SCRIPT_DIR, "Config.h")
- maj = min_ = None
- try:
- with open(cfg, "rb") as f:
- for raw in f:
- line = raw.decode("utf-8", errors="replace").strip()
- if line.startswith("#define MAJ_VERS"):
- maj = "%01d" % ord(bytes.fromhex(line.split()[2].split("x")[1]))
- if line.startswith("#define MIN_VERS"):
- min_ = "%02d" % ord(bytes.fromhex(line.split()[2].split("x")[1]))
- except Exception as e:
- print(f"Warning: could not read version from Config.h: {e}")
- return f"{maj}.{min_}" if maj and min_ else "unknown"
-
-
-def create_zip(merged_paths, output_path):
- """Create the release ZIP from merged binaries and extra files."""
- os.makedirs(os.path.dirname(output_path), exist_ok=True)
- with zipfile.ZipFile(output_path, "w", zipfile.ZIP_DEFLATED) as zf:
- for merged in merged_paths:
- arcname = os.path.basename(merged)
- zf.write(merged, arcname)
- print(f" + {arcname}")
- for local_path, arcname in EXTRA_FILES:
- full = os.path.join(SCRIPT_DIR, local_path)
- if os.path.isfile(full):
- zf.write(full, arcname)
- print(f" + {arcname}")
- else:
- print(f" (skip {arcname} — not found)")
- size = os.path.getsize(output_path)
- digest = sha256_file(output_path)
- print(f"\n Archive: {output_path}")
- print(f" Size: {size:,} bytes")
- print(f" SHA-256: {digest}")
- return digest
-
-
-def write_hashes(merged_paths, version, output_dir):
- """Write release_hashes.json next to the ZIP."""
- hashes = {}
- for path in merged_paths:
- name = os.path.basename(path)
- hashes[name] = {
- "hash": sha256_file(path),
- "version": version,
- }
- out = os.path.join(output_dir, "release_hashes.json")
- with open(out, "w") as f:
- json.dump(hashes, f, indent=2)
- print(f"\n Hashes written: {out}")
-
-
-def main():
- parser = argparse.ArgumentParser(description="Build and package RTNode firmware release")
- parser.add_argument("--no-build", action="store_true",
- help="Skip PlatformIO build — use existing .pio/build output")
- parser.add_argument("--output", "-o", default=OUTPUT_ZIP,
- help=f"Output ZIP path (default: {OUTPUT_ZIP})")
- parser.add_argument("--envs", nargs="*",
- help="Limit to specific PIO envs (e.g. heltec_V3_boundary)")
- args = parser.parse_args()
-
- version = read_version()
- print(f"\nRTNode Release Packager — firmware version {version}")
- print("=" * 55)
-
- # Filter envs if requested
- envs = BUILD_ENVS
- if args.envs:
- envs = [e for e in BUILD_ENVS if e["pio_env"] in args.envs]
- if not envs:
- print(f"Error: no matching envs in {args.envs}")
- sys.exit(1)
-
- pio = find_pio()
- esptool_cmd = find_esptool()
- boot_app0 = find_boot_app0()
-
- if not pio and not args.no_build:
- print("Error: PlatformIO not found. Install from https://platformio.org")
- print("Or use --no-build to skip the build step.")
- sys.exit(1)
-
- if not esptool_cmd:
- print("Error: esptool not found. Install with: pip install esptool")
- sys.exit(1)
-
- if not boot_app0:
- print("Error: boot_app0.bin not found in PlatformIO packages.")
- print("Run 'pio run -e heltec_V3_boundary' once to install framework packages.")
- sys.exit(1)
-
- print(f"\nPlatformIO: {pio or '(skipped)'}")
- print(f"esptool: {' '.join(esptool_cmd)}")
- print(f"boot_app0: {boot_app0}")
- print(f"Output ZIP: {args.output}")
-
- # ── Build ──────────────────────────────────────────────────────────────
- if not args.no_build:
- print("\n── Build ──────────────────────────────────────────────────────────")
- for env_cfg in envs:
- if not build_env(env_cfg, pio):
- sys.exit(1)
- else:
- print("\n(--no-build: skipping PlatformIO build)")
-
- # ── Merge ──────────────────────────────────────────────────────────────
- print("\n── Merge ──────────────────────────────────────────────────────────")
- merged_paths = []
- for env_cfg in envs:
- path = merge_env(env_cfg, esptool_cmd, boot_app0)
- if not path:
- sys.exit(1)
- merged_paths.append(path)
-
- # ── Package ────────────────────────────────────────────────────────────
- print("\n── Package ────────────────────────────────────────────────────────")
- digest = create_zip(merged_paths, args.output)
-
- write_hashes(merged_paths, version, os.path.dirname(args.output))
-
- print()
- print("╔══════════════════════════════════════════╗")
- print("║ Release package complete! ║")
- print("╚══════════════════════════════════════════╝")
- print()
- print("Next steps:")
- print(f" 1. Copy the platform-specific esptool binary into the ZIP:")
- print(f" Release/esptool/esptool (macOS / Linux)")
- print(f" Release/esptool/esptool.exe (Windows)")
- print(f" Or add it to the ZIP: zip {args.output} Release/esptool/esptool")
- print(f" 2. Upload {args.output} to GitHub Releases as '{os.path.basename(args.output)}'")
- print(f" 3. Tag the release — flash.py will detect and download it automatically")
-
-
-if __name__ == "__main__":
- main()

diff --git a/platformio.ini b/platformio.ini
index 47f1c30..a72b3f7 100755
--- a/platformio.ini
+++ b/platformio.ini
@@ -353,41 +353,6 @@ lib_deps =
${env.lib_deps}
XPowersLib@^0.2.1
-[env:heltec_V4_boundary]
-platform = espressif32
-board = esp32-s3-devkitc-1
-custom_variant = heltec32v4_boundary_8mb
-board_build.filesystem = littlefs
-; Flash / memory layout for 8MB flash + 2MB PSRAM
-board_upload.flash_size = 8MB
-board_upload.maximum_size = 8388608
-board_build.partitions = default_8MB.csv
-board_build.flash_mode = qio
-board_build.psram_type = qio
-board_build.arduino.memory_type = qio_qspi
-monitor_speed = 115200
-build_flags =
- ${env.build_flags}
- -DBOARD_MODEL=BOARD_HELTEC32_V4
- -DARDUINO_USB_CDC_ON_BOOT=1
- -DBOARD_HAS_PSRAM=1
- -DBOUNDARY_MODE
- ;-DNDEBUG
- -DRNS_USE_TLSF=1
- -DRNS_USE_ALLOCATOR=1
- ; --- Boundary mode defaults (override via EEPROM at runtime) ---
- ; TCP server mode (0=server, 1=client)
- -DBOUNDARY_TCP_MODE=0
- ; TCP listen/connect port
- -DBOUNDARY_TCP_PORT=4242
- ; Backbone host for client mode (empty = server mode)
- ; -DBOUNDARY_BACKBONE_HOST=\"192.168.1.100\"
- ; -DBOUNDARY_BACKBONE_PORT=4242
-lib_deps =
- ${env.lib_deps}
- XPowersLib@^0.2.1
-monitor_filters = esp32_exception_decoder
-
[env:heltec_V4_boundary_16mb]
platform = espressif32
board = esp32-s3-devkitc-1

Served by rngit 1.4.2 - Generated in 0.05s